﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Text.RegularExpressions;

namespace DAO
{
    /// <summary>
    /// Lớp cung cấp các phương thức kết nối và làm việc với csdl
    /// </summary>
    public class Helper
    {
        #region Variables

        private SqlCommand _cmd;
        private SqlConnection _conn;

        #endregion

        #region Methods

        /// <summary>
        /// Lấy thông tin kết nối
        /// </summary>
        /// <returns>SqlConnection</returns>
        private SqlConnection GetConnection()
        {
            const string connString = "Data source=.;Initial catalog=QLBH;Integrated security=true";
            return new SqlConnection(connString);
        }

        /// <summary>
        /// Thực hiện stored procedure SQL
        /// </summary>
        /// <param name="query">Tên stored procedure hoặc sql query</param>
        /// <param name="commandType">Kiểu của SqlCommand, ở đây sử dụng CommandType.Procedure</param>
        /// <param name="parameters">Đối tượng chứa tên biến và giá trị tương ứng</param>
        /// <returns>> 0 nếu thành công, thất bại thì ngược lại</returns>
        public int ExecuteNonQuery(string query, CommandType commandType, params Object[] parameters)
        {
            _conn = GetConnection();
            _cmd = new SqlCommand(query, _conn) {CommandType = commandType};
            SetValueOfParameters(ref _cmd, parameters);
            _conn.Open();
            return _cmd.ExecuteNonQuery();
        }


        /// <summary>
        /// Get DataTable
        /// </summary>
        /// <param name="table">Tên bảng</param>
        /// <returns>DataTable</returns>
        public DataTable GetDataTable(string table)
        {
            _conn = GetConnection();
            var da = new SqlDataAdapter(table, _conn);
            var dataTable = new DataTable();
            _conn.Open();
            da.Fill(dataTable);
            return dataTable;
        }


        /// <summary>
        /// Get DataSet
        /// </summary>
        /// <param name="query">Sql query</param>
        /// <returns>DataSet</returns>
        public DataSet GetDataSet(string query)
        {
            _conn = GetConnection();
            var da = new SqlDataAdapter(query, _conn);
            DataSet ds = new DataSet("dataset1");
            da.Fill(ds);
            return ds;
        }

        /// <summary>
        /// Gán giá trị cho các biến khi sử dụng store procedure.
        /// Phải sử dụng từ khóa ref ở đây để cho chương trình biết rằng cmd là một biến 
        /// kiểu tham chiếu. Tức là một khi đối tượng này được thay đổi ở bất kì đâu thì giá trị
        /// các ô nhở của nó cũng thay đổi theo. Ngược lại nếu không khai báo ref thì nó sẽ là kiểu
        /// tham trị - Giá trị chỉ được copy vào ô nhớ => thoát khỏi hàm này, giá trị vẫn như lúc
        /// ban đầu.
        /// </summary>
        /// <param name="cmd">Đối tượng command chứa stored procedure cần gán giá trị</param>
        /// <param name="parameters">Đối tượng chứa tên biến và giá trị tương ứng</param>
        private void SetValueOfParameters(ref SqlCommand cmd, params Object[] parameters)
        {
            // Nếu danh sách biến và giá trị tương ứng rỗng thì thoát khỏi hàm
            if (parameters == null) return;

            /** 
             * VD: Mảng paramteres sẽ có dữ liệu như sau: 
             * 
             *                       paramerters[] ={@p1, 1, @p2, 2}
             *                              
             * Mảng được bắt đầu từ vị trí 0 và mỗi biến chiếm 2 ô nhớ của mảng 
             * (@p1 - tên biến, 1 - giá trị của biến) nên bước nhảy của vòng lặp là 2 (i+=2)
             **/

            for (int i = 0; i < parameters.Length; i += 2)
            {
                // Tên biến có ô nhớ thứ i, value = i+1
                _cmd.Parameters.AddWithValue(parameters[i].ToString(), parameters[i + 1]);
            }
        }

        /// <summary>
        /// Ngắt kết nối
        /// </summary>
        public void Disconnect()
        {
            // Nếu kết nối đã được đóng thì thoát khỏi hàm 
            if (!_conn.State.Equals(ConnectionState.Open)) return;
            _conn.Close();
            _conn.Dispose();
        }

        /// <summary>
        /// Tự tăng phần số của ID.
        /// Hàm này sẽ tách phần số trong id (bao gồm cả chữ và số) 
        /// sau đó tăng phần số này lên 1 đơn vị
        /// </summary>
        /// <param name="table">Tên bảng</param>
        /// <param name="column">Cột cần tự tăng giá trị</param>
        /// <returns>Id</returns>
        public int AutoIncrementID(string table, string column)
        {
            int intId = 0;
            DataTable dataTable =
                GetDataTable(string.Format("select top 1 {0} from {1} order by {0} desc", column, table));

            if (dataTable.Rows.Count == 0) return 1;

            string strID = dataTable.Rows[0][0].ToString();
            Match regex = Regex.Match(strID, @"(\d+|[A-Za-z]+)");

            if (regex.Success)
            {
                intId = int.Parse(strID.Substring(regex.Length));
                intId++;
            }

            return intId;
        }
            
        ///// <summary>
        ///// Lấy ra dan sách các cột có tromg SqlDataReader
        ///// </summary>
        ///// <param name="reader">Đối tượng SqlDataReader</param>
        ///// <returns>Danh sách cột</returns>
        //public IList<String> GetColumnNameOfDtReader(SqlDataReader reader)
        //{
        //    IList<String> lstCol = new List<string>();
        //    for (var i = 0; i < reader.FieldCount; i++)
        //    {
        //        lstCol.Add(reader.GetName(i));
        //    }
        //    return lstCol;
        //}

        #endregion
    }
}